﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using CmdArgs.Validation;
using CmdArgs.Validation.Options;
using CmdArgs.Settings;
using CmdArgs;

namespace AdvancedUsage
{
    class Program
    {
        /// <summary>
        /// Custom validator example.
        /// </summary>
        class PalindromValidator : ValueValidatorTemplate
        {
            protected override ValidationResult Validate(string value, OptionSettings option)
            {
                if (value == this.Reverse(value))
                {
                    return ValidationResult.GetValidResult();
                }
                else
                {
                    return new ValidationResult(new ValidationError("Hodnota neni palindrom", option));
                }
            }

            private string Reverse(string str)
            {
                return new string(str.ToCharArray().Reverse().ToArray());
            }
        }


        /// <summary>
        /// Implementation of TypeConverter may be useful also for easier usage of CmdArgs library.
        /// </summary>
        class PointConverter : TypeConverter
        {
            public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
            {
                if ((value is string) == false)
                {
                    return base.ConvertFrom(context, culture, value);
                }

                int[] nums = ((string)value).Split(',').Select(s => int.Parse(s)).ToArray();
                return new Point() { X = nums[0], Y = nums[1] };
            }

            public override bool IsValid(ITypeDescriptorContext context, object value)
            {
                try
                {
                    this.ConvertFrom(value);
                }
                catch (Exception ex)
                {
                    return false;
                }

                return true;
            }
        }

        /// <summary>
        /// Custom data structure that will be parsed using CmdArgs library.
        /// </summary>
        [TypeConverter(typeof(PointConverter))]
        class Point
        {
            public int X { get; set; }
            public int Y { get; set; }

            public override string ToString()
            {
                return string.Format("Point ToString method, values X={0}, Y={0}", this.X, this.Y);
            }
        }


        static void Main(string[] args)
        {
            args = new[] { "--help" };
            var settingsBuilder = new SettingsBuilder();

            settingsBuilder.AddFlag("help", 'h');

            settingsBuilder.AddOption("point", 'p', OptionParametersCount.Exactly(1))
                .SetParameterName("Point")
                .SetDescription("Demonstrates parsing of parameter of custom type. Point should be in format [X,Y].")
                .AddValidator(new GenericOptionValidator<Point>());

            settingsBuilder.AddOption("palindrom", 'a', OptionParametersCount.AtLeast(1))
                .SetParameterName("Palindrom")
                .SetDescription("Demonstrates custom validator. Parameters must be palindroms.")
                .AddValidator(new PalindromValidator());

            var parser = new CommandLineParser(settingsBuilder.ToSettings());
            var validationResult = parser.Validate(args);

            if (!validationResult.IsValid)
            {
                Console.WriteLine("Arguments are not valid");
                Console.WriteLine("Try --help");
                validationResult.WriteErrorsToConsole();
                return;
            }

            var result = parser.Parse(args);

            if (result.Options.Contains("help"))
            {
                settingsBuilder.ToSettings().WriteHelpToConsole();
            }
            else
            {
                if (result.Options.Contains("point"))
                {
                    Point p = result.Options["point"].Value.As<Point>();
                    Console.WriteLine("Given point: {0}", p);
                }

                if (result.Options.Contains("palindrom"))
                {
                    Console.WriteLine("Given palindroms are: {0}",
                        string.Join(", ", result.Options["palindrom"].Values.Select(v => v.Value).ToArray()));
                }

                if (result.Arguments.Count() > 0)
                {
                    Console.WriteLine("Ordinary arguments: {0}",
                        string.Join(", ", result.Arguments.ToArray()));
                }
            }
        }
    }
}
